package edu.byu.isys413.group1E.handlers;

//import PaddedDecimalFormat;
import java.util.*;
import java.text.*;

/**Calculates the difference between two dates
 *
 * @author tkulbeth
 */

public class DateDiff {
   // set some constants that allow pretty accurate estimates over
   //  about 2,000 years before or after the present.  These are
   //  slight overestimates since that's what we want (and need!)
   private static final double DAY_MILLIS = 1000*60*60 * 24.0015;
   private static final double WEEK_MILLIS = DAY_MILLIS * 7;
   private static final double MONTH_MILLIS = DAY_MILLIS * 30.43675;
   private static final double YEAR_MILLIS = WEEK_MILLIS * 52.2;

    /**
     * 
     * @param calUnit 
     * @param d1 
     * @param d2 
     * @return 
     */
   protected int getDateDiff( int calUnit, Date d1, Date d2 ) {
      // swap if d1 later than d2
      boolean neg = false;
      if( d1.after(d2) ) {
         Date temp = d1;
         d1 = d2;
         d2 = temp;
         neg = true;
      }

      // estimate the diff.  d1 is now guaranteed <= d2
      int estimate = (int)getEstDiff( calUnit, d1, d2 );

      // convert the Dates to GregorianCalendars
      GregorianCalendar c1 = new GregorianCalendar();
      c1.setTime(d1);
      GregorianCalendar c2 = new GregorianCalendar();
      c2.setTime(d2);

      // add 2 units less than the estimate to 1st date,
      //  then serially add units till we exceed 2nd date
      c1.add( calUnit, (int)estimate - 2 );
      for( int i=estimate-1; ; i++ ) {         
         c1.add( calUnit, 1 );
         if( c1.after(c2) )
            return neg ? 1-i : i-1;
      }
   }

   private int getEstDiff( int calUnit, Date d1, Date d2 ) {
      long diff = d2.getTime() - d1.getTime();
      switch (calUnit) {
      case Calendar.DAY_OF_WEEK_IN_MONTH :
      case Calendar.DAY_OF_MONTH :
//      case Calendar.DATE :      // codes to same int as DAY_OF_MONTH
         return (int) (diff / DAY_MILLIS + .5);  
      case Calendar.WEEK_OF_YEAR :
         return (int) (diff / WEEK_MILLIS + .5);
      case Calendar.MONTH :
         return (int) (diff / MONTH_MILLIS + .5);
      case Calendar.YEAR :
         return (int) (diff / YEAR_MILLIS + .5);
      default:
         return 0;
      } /* endswitch */
   }

   // some test code...
    /**
     * 
     * @param args 
     */
   public static void main(String[] args) {
      DateDiff dd = new DateDiff();
      Date then = null, now = null;
      DateFormat df = DateFormat.getInstance();
//      DecimalFormat ddf = (DecimalFormat)NumberFormat.getInstance();
//      ddf.setMaximumFractionDigits(0);

      // Use this instead of DecimalFormat if you have it...
      // If not, you can get it at:
      // http://pws.prserv.net/ad/programs/Programs.html#PaddedDecimalFormat
      
      PaddedDecimalFormat ddf = PaddedDecimalFormat.getNumberInstance(0, Locale.getDefault());

      df.setTimeZone( TimeZone.getDefault() );
      if (args.length < 2) {
         String pattern = ((SimpleDateFormat)df).toLocalizedPattern();
         
         System.out.println("Usage: Enter two dates in this format: " 
                          + pattern.substring( 0, pattern.indexOf(' ')) );
         System.exit(0);
      } else {
         try {
            then = df.parse( args[0] + " 12:00 PM" );
            now = df.parse( args[1] + " 12:00 PM" );
         } catch ( ParseException e ) {
            System.out.println("Couldn't parse date: " + e );
            System.exit(1);
         } /* endcatch */
      } /* endif */
      
      // now we have two Date objects.  get real & estimated diff
      int diff = dd.getDateDiff( Calendar.DATE, then, now );  
      System.out.println("Interval in days:   " 
                        + ddf.format( diff, 20 ) );
//                        + ddf.format( diff ) );
      diff = dd.getDateDiff( Calendar.WEEK_OF_YEAR, then, now );
      System.out.println("Interval in weeks:  " 
                        + ddf.format( diff, 20 ) );
//                        + ddf.format( diff ) );
      diff = dd.getDateDiff( Calendar.MONTH, then, now );
      System.out.println("Interval in months: " 
                        + ddf.format( diff, 20 ) );
//                        + ddf.format( diff ) );
      diff = dd.getDateDiff( Calendar.YEAR, then, now );
      System.out.println("Interval in years:  " 
                        + ddf.format( diff, 20 ) );
//                        + ddf.format( diff ) );
   }
}
/* Example output of test code:
[F:\test]java DateDiff 5/29/1066 5/29/1999
   Interval in days:                340,765 
   Interval in weeks:                48,680 
   Interval in months:               11,196 
   Interval in years:                   933 
*/
